﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace KnowlegeAssistant
{
    public partial class TestProcessForm : Form
    {
        private Theme theme;

        private int archive_test_id = 0;

        private User user;

        private int current_level = 1;

        private List<Question> first_questions;
        private List<Question> second_questions;
        private List<Question> second_questions_type2;

        private List<List<Answer>> first_answers;
        private List<List<Answer>> second_answers;

        private List<Question> questions;
        private List<List<Answer>> answers;

        private int current_minute = 0;
        private int current_second = 0;
        private int current_question_index = -1;
        private int countOfGaveAnswers = 0;
        private int user_id = 0;
        private DateTime date_begin;

        private List<Control> ansControlForSecondQuestions = new List<Control>();
        private List<Control> ansControlForThirdQuestions = new List<Control>();

        public TestProcessForm(Theme theme, int user_id, User user)
        {
            InitializeComponent();

            this.user = user;
            this.user_id = user_id;
            this.theme = theme;

            this.themename.Text = theme.Name;
            this.subjectname.Text = theme.Subject.Name;
            this.testtime.Text = theme.Duration.ToString();

            InitQuestions();
            InitAnswers();

            question_number.Text = (first_questions.Count + second_questions.Count).ToString();
            
            test_timer.Interval = 1000;
            test_timer.Tick += new EventHandler(test_timer_Tick);

            this.ansControlForSecondQuestions.AddRange(new List<Control>()
            {
                answer_rb1,answer_rb2,answer_rb3,answer_rb4,answer_rb5,answer_rb6
            });

            this.ansControlForThirdQuestions.AddRange(new List<Control>()
            {
                answer_cb1,answer_cb2,answer_cb3,answer_cb4,answer_cb5,answer_cb6
            });
        }

        private void InitQuestions()
        {
            first_questions = TestUtil.GetThemeQuestionsByType(theme, 1);
            second_questions = TestUtil.GetThemeQuestionsByType(theme, 2);
            second_questions_type2 = TestUtil.GetThemeQuestionsByType(theme, 3);

            int countOffirstQuestions = theme.CountOfFirstQuestions;
            int countOfsecondQuestions = theme.CountOfSecondQuestionsType1;
            int countOfthirdQuestions = theme.CountOfSecondQuestionsType2;

            int countOfFirstlevel = (int)(countOffirstQuestions * 50.0 / 100.0);
            int countOfSecondlevel = (int)(countOffirstQuestions * 30.0 / 100.0);
            int countOfThirdlevel = (int)(countOffirstQuestions * 20.0 / 100.0);

            InitFirstQuestions(countOfThirdlevel, countOfSecondlevel, countOfFirstlevel, countOffirstQuestions);

            countOfFirstlevel = (int)(countOfsecondQuestions * 50.0 / 100.0);
            countOfSecondlevel = (int)(countOfsecondQuestions * 30.0 / 100.0);
            countOfThirdlevel = (int)(countOfsecondQuestions * 20.0 / 100.0);

            InitSecondQuestions(countOfThirdlevel, countOfSecondlevel, countOfFirstlevel, countOfsecondQuestions);

            countOfFirstlevel = (int)(countOfthirdQuestions * 50.0 / 100.0);
            countOfSecondlevel = (int)(countOfthirdQuestions * 30.0 / 100.0);
            countOfThirdlevel = (int)(countOfthirdQuestions * 20.0 / 100.0);

            InitThirdQuestions(countOfThirdlevel, countOfSecondlevel, countOfFirstlevel, countOfthirdQuestions);

            //while (first_questions.Count != countOffirstQuestions)
            //{
            //    first_questions.RemoveAt(rand.Next(0, first_questions.Count));
            //}

            //while (second_questions.Count != countOfsecondQuestions)
            //{
            //    second_questions.RemoveAt(rand.Next(0, second_questions.Count));
            //}

            //while (second_questions_type2.Count != countOfthirdQuestions)
            //{
            //    second_questions_type2.RemoveAt(rand.Next(0, second_questions_type2.Count));
            //}

            second_questions.AddRange(second_questions_type2);

            questions = new List<Question>() { };

            questions.AddRange(first_questions.OrderBy(q => q.QuestionID).ToList());
            questions.AddRange(second_questions.OrderBy(q => q.QuestionID).ToList());
        }

        private void InitFirstQuestions(int countOfThirdlevel, int countOfSecondlevel, int countOfFirstlevel, int countOffirstQuestions)
        {
            Random rand = new Random();

            List<Question> tempFirst = new List<Question>();

            tempFirst.AddRange(first_questions);
            List<Question> t = tempFirst.Where(o => o.LevelValue == 3).ToList();

            while (t.Count > countOfThirdlevel)
            {
                tempFirst.Remove(t[rand.Next(0, t.Count)]);
                t = tempFirst.Where(o => o.LevelValue == 3).ToList();
            }

            t = tempFirst.Where(o => o.LevelValue == 2).ToList();

            while (t.Count > countOfSecondlevel)
            {
                tempFirst.Remove(t[rand.Next(0, t.Count)]);
                t = tempFirst.Where(o => o.LevelValue == 2).ToList();
            }

            t = tempFirst.Where(o => o.LevelValue == 1).ToList();

            while (t.Count > countOfFirstlevel)
            {
                tempFirst.Remove(t[rand.Next(0, t.Count)]);
                t = tempFirst.Where(o => o.LevelValue == 1).ToList();
            }

            int level = 1;
            while (tempFirst.Count < countOffirstQuestions)
            {
                List<Question> q = first_questions.Where(o => o.LevelValue == level).ToList();
                if (q.Count != 0)
                {
                    if (!tempFirst.Contains(q[0])) { tempFirst.Add(q[0]); }
                    else { first_questions.Remove(q[0]); }
                }
                else { level++; }
            }

            first_questions.Clear();
            first_questions.AddRange(tempFirst.OrderBy(o=>o.QuestionID).ToList());
        }

        private void InitSecondQuestions(int countOfThirdlevel, int countOfSecondlevel, int countOfFirstlevel, int countOfSecondQuestions)
        {
            Random rand = new Random();

            List<Question> tempSecond = new List<Question>();

            tempSecond.AddRange(second_questions);
            List<Question> t = tempSecond.Where(o => o.LevelValue == 3).ToList();

            while (t.Count > countOfThirdlevel)
            {
                tempSecond.Remove(t[rand.Next(0, t.Count)]);
                t = tempSecond.Where(o => o.LevelValue == 3).ToList();
            }

            t = tempSecond.Where(o => o.LevelValue == 2).ToList();

            while (t.Count > countOfSecondlevel)
            {
                tempSecond.Remove(t[rand.Next(0, t.Count)]);
                t = tempSecond.Where(o => o.LevelValue == 2).ToList();
            }

            t = tempSecond.Where(o => o.LevelValue == 1).ToList();

            while (t.Count > countOfFirstlevel)
            {
                tempSecond.Remove(t[rand.Next(0, t.Count)]);
                t = tempSecond.Where(o => o.LevelValue == 1).ToList();
            }

            int level = 1;
            while (tempSecond.Count < countOfSecondQuestions)
            {
                List<Question> q = second_questions.Where(o => o.LevelValue == level).ToList();
                if (q.Count != 0)
                {
                    if (!tempSecond.Contains(q[0])) { tempSecond.Add(q[0]); }
                    else { second_questions.Remove(q[0]); }
                }
                else { level++; }
            }

            second_questions.Clear();
            second_questions.AddRange(tempSecond.OrderBy(o => o.QuestionID).ToList());
        }

        private void InitThirdQuestions(int countOfThirdlevel, int countOfSecondlevel, int countOfFirstlevel, int countOfThirdQuestions)
        {
            Random rand = new Random();

            List<Question> tempThird = new List<Question>();

            tempThird.AddRange(second_questions_type2);
            List<Question> t = tempThird.Where(o => o.LevelValue == 3).ToList();

            while (t.Count > countOfThirdlevel)
            {
                tempThird.Remove(t[rand.Next(0, t.Count)]);
                t = tempThird.Where(o => o.LevelValue == 3).ToList();
            }

            t = tempThird.Where(o => o.LevelValue == 2).ToList();

            while (t.Count > countOfSecondlevel)
            {
                tempThird.Remove(t[rand.Next(0, t.Count)]);
                t = tempThird.Where(o => o.LevelValue == 2).ToList();
            }

            t = tempThird.Where(o => o.LevelValue == 1).ToList();

            while (t.Count > countOfFirstlevel)
            {
                tempThird.Remove(t[rand.Next(0, t.Count)]);
                t = tempThird.Where(o => o.LevelValue == 1).ToList();
            }

            int level = 1;
            while (tempThird.Count < countOfThirdQuestions)
            {
                List<Question> q = second_questions_type2.Where(o => o.LevelValue == level).ToList();
                if (q.Count != 0)
                {
                    if (!tempThird.Contains(q[0])) { tempThird.Add(q[0]); }
                    else { second_questions_type2.Remove(q[0]); }
                }
                else { level++; }
            }

            second_questions_type2.Clear();
            second_questions_type2.AddRange(tempThird.OrderBy(o => o.QuestionID).ToList());
        }

        private void InitAnswers()
        {
            first_answers = new List<List<Answer>>();
            second_answers = new List<List<Answer>>();

            first_questions = first_questions.OrderBy(q => q.QuestionID).ToList();

            foreach (Question q in first_questions)
            {
                first_answers.Add(TestUtil.GetQuestionAnswersByQuestion(q));
            }

            second_questions = second_questions.OrderBy(q => q.QuestionID).ToList();

            foreach (Question q in second_questions)
            {
                second_answers.Add(TestUtil.GetQuestionAnswersByQuestion(q));
            }

            answers = new List<List<Answer>>() { };
            answers.AddRange(first_answers);
            answers.AddRange(second_answers);
        }

        void test_timer_Tick(object sender, EventArgs e)
        {

            this.current_second++;
            this.current_minute = (this.current_second == 60) ? this.current_minute + 1 : this.current_minute;
            this.current_second = (this.current_second == 60) ? 0 : this.current_second;

            current_time.Text =
                this.current_minute + ":" +
                ((this.current_second < 10) ? "0" + current_second : current_second.ToString());

            if (this.current_minute == theme.Duration)
            {
                test_timer.Stop();
                MessageBox.Show("Время вышло");
            }
        }

        private void start_test_button_Click(object sender, EventArgs e)
        {
            StartingTest();
            ans_btn.Enabled = true;
            nextq_btn.Enabled = true;
            test_timer.Start();
            date_begin = DateTime.Now;
        }

        private void ShowNextQuestionFromFirstLevel()
        {
            current_question_index = GetNextNotAnsweredQuestionIndexForFirstLevel();

            setFalseVisibleToAnswers();
            question_grbox.Text = "Вопрос №" + (current_question_index + 1);
            question_description.Text = questions[current_question_index].Description;

            SetQuestionImage();

            int type = questions[current_question_index].Type;

            if (type == 1)
            {
                level_grbox.Text = "Этап №1";
                answer_rb1.Visible = true;
                answer_rb1.Checked = true;
                answer_rb2.Visible = true;
                answer_rb1.Text = answers[current_question_index][0].Description;
                answer_rb2.Text = answers[current_question_index][1].Description;
            }
        }

        private void SetQuestionImage()
        {
            if (questions[current_question_index].Image != null)
            {
                question_imagepictureBox.Image = questions[current_question_index].Image;
                question_imagepictureBox.Visible = true;
                question_description.BringToFront();
            }
            else
            {
                question_imagepictureBox.Visible = false;
                question_description.SendToBack();
            }
        }

        private void ShowNextQuestionFromSecondLevel()
        {
            current_question_index = GetNextNotAnsweredQuestionIndexForSecondLevel();

            setFalseVisibleToAnswers();
            question_grbox.Text = "Вопрос №" + (current_question_index + 1 - first_questions.Count);
            question_description.Text = questions[current_question_index].Description;

            SetQuestionImage();

            int type = questions[current_question_index].Type;
            level_grbox.Text = "Этап №2";

            if (type == 2)
            {
                for (int i = 0; i < answers[current_question_index].Count; i++)
                {
                    ((RadioButton)ansControlForSecondQuestions[i]).Visible = true;
                    ((RadioButton)ansControlForSecondQuestions[i]).Text = answers[current_question_index][i].Description;
                }

                if (answers[current_question_index].Count > 0)
                {
                    ((RadioButton)ansControlForSecondQuestions[0]).Checked = true;
                }
            }
            else if (type == 3)
            {
                for (int i = 0; i < answers[current_question_index].Count; i++)
                {
                    ((CheckBox)ansControlForThirdQuestions[i]).Visible = true;
                    ((CheckBox)ansControlForThirdQuestions[i]).Text = answers[current_question_index][i].Description;
                }
            }
        }

        private void setFalseVisibleToAnswers()
        {
            for (int i = 0; i < ansControlForSecondQuestions.Count; i++)
            {
                ((RadioButton)ansControlForSecondQuestions[i]).Visible = false;
                ((RadioButton)ansControlForSecondQuestions[i]).Checked = false;
            }

            for (int i = 0; i < ansControlForThirdQuestions.Count; i++)
            {
                ((CheckBox)ansControlForThirdQuestions[i]).Visible = false;
                ((CheckBox)ansControlForThirdQuestions[i]).Checked = false;
            }
        }

        private int GetNextNotAnsweredQuestionIndexForFirstLevel()
        {
            for (int i = current_question_index + 1; i < questions.Count; i++)
            {
                if (!questions[i].Answered && questions[i].Type == 1)
                {
                    return i;
                }
            }

            for (int i = 0; i < current_question_index + 1; i++)
            {
                if (!questions[i].Answered && questions[i].Type == 1)
                {
                    return i;
                }
            }

            return -1;
        }

        private int GetNextNotAnsweredQuestionIndexForSecondLevel()
        {
            for (int i = current_question_index + 1; i < questions.Count; i++)
            {
                if (!questions[i].Answered && (questions[i].Type == 2 || questions[i].Type == 3))
                {
                    return i;
                }
            }

            for (int i = 0; i < current_question_index + 1; i++)
            {
                if (!questions[i].Answered && (questions[i].Type == 2 || questions[i].Type == 3))
                {
                    return i;
                }
            }

            return -1;
        }

        private void end_test_button_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.DialogResult dr =
                MessageBox.Show("У вас остались неотвеченные вопросы! Вы действительно хотите завершить тест?", "ВНИМАНИЕ!",
                 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (dr == System.Windows.Forms.DialogResult.Yes)
            {
                FinishTest();
            }
        }

        private void StartingTest()
        {
            end_test_button.Enabled = true;
            start_test_button.Enabled = false;
            results_button.Enabled = false;

            ShowNextQuestionFromFirstLevel();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (current_level == 1)
            {
                ShowNextQuestionFromFirstLevel();
            }
            else if (current_level == 2)
            {
                ShowNextQuestionFromSecondLevel();
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            int type = questions[current_question_index].Type;

            if (type == 1)
            {
                if (answer_rb1.Checked)
                {
                    answers[current_question_index][0].Checked = true;
                }
                else
                {
                    answers[current_question_index][1].Checked = true;
                }
            }
            else if (type == 2)
            {
                for (int i = 0; i < answers[current_question_index].Count; i++)
                {
                    if (((RadioButton)ansControlForSecondQuestions[i]).Checked == true)
                    {
                        answers[current_question_index][i].Checked = true;
                    }
                    else
                    {
                        answers[current_question_index][i].Checked = false;
                    }
                }
            }
            else if (type == 3)
            {
                for (int i = 0; i < answers[current_question_index].Count; i++)
                {
                    if (((CheckBox)ansControlForThirdQuestions[i]).Checked == true)
                    {
                        answers[current_question_index][i].Checked = true;
                    }
                    else
                    {
                        answers[current_question_index][i].Checked = false;
                    }
                }
            }

            countOfGaveAnswers++;
            this.answers_number.Text = countOfGaveAnswers.ToString();

            questions[current_question_index].Answered = true;

            if (current_level == 1 && GetNextNotAnsweredQuestionIndexForFirstLevel() != -1)
            {
                ShowNextQuestionFromFirstLevel();
            }
            else if (current_level == 1 && GetNextNotAnsweredQuestionIndexForFirstLevel() == -1)
            {
                if (IsPassedFirstLevel())
                {
                    MessageBox.Show("Первый этап успешно завершен");
                    current_level = 2;
                    ShowNextQuestionFromSecondLevel();
                }
                else
                {
                    MessageBox.Show("Вы не набрали более 40% правильных ответов на первом этапе. Тестирование завершено.");
                    FinishTest();
                }
            }
            else if (current_level == 2 && GetNextNotAnsweredQuestionIndexForSecondLevel() != -1)
            {
                ShowNextQuestionFromSecondLevel();
            }
            else
            {
                FinishTest();
            }
        }

        private void FinishTest()
        {
            end_test_button.Enabled = false;
            start_test_button.Enabled = false;
            results_button.Enabled = true;
            nextq_btn.Enabled = false;
            ans_btn.Enabled = false;
            question_description.Text = "";

            setFalseVisibleToAnswers();

            test_timer.Stop();

            this.archive_test_id = TestUtil.CreateTestResults(
                this.theme,
                this.questions,
                this.answers,
                this.user_id,
                current_minute * 60 + current_second,
                date_begin
             );

            MessageBox.Show("Тестирование завершено. Выможете посмотреть результаты тестирования нажав на кнопку \"Результаты\"");
        }

        private void results_button_Click(object sender, EventArgs e)
        {
            StatisticsForm sf = new StatisticsForm(0, 0, archive_test_id,this.user);
            sf.ShowDialog();
        }

        private bool IsPassedFirstLevel()
        {
            int trueanswer = 0;
            int falseanswer = 0;
            for (int i = 0; i < first_answers.Count; i++)
            {
                if (first_answers[i][0].Checked && first_answers[i][0].True)
                {
                    trueanswer++;
                }
                else if (first_answers[i][1].Checked && first_answers[i][1].True)
                {
                    trueanswer++;
                }
                else { falseanswer++; }
            }
            return (trueanswer * 100.0 / (trueanswer + falseanswer)) > 40.0;
        }

        private void TestProcessForm_Load(object sender, EventArgs e)
        {

        }

        private void level_grbox_Enter(object sender, EventArgs e)
        {

        }

        private void question_imagepictureBox_Click(object sender, EventArgs e)
        {
            if (this.question_imagepictureBox.Image != null)
            {
                FullPictureViewForm fppf = new FullPictureViewForm(this.question_imagepictureBox.Image);
                fppf.ShowDialog();
            }
        }

    }
}
